package com.tool.shiro.realm;

import com.tool.shiro.pojo.ShiroPermission;
import com.tool.shiro.pojo.ShiroRole;
import com.tool.shiro.pojo.ShiroAdminManage;
import com.tool.shiro.salt.MyByteSource;
import com.tool.shiro.service.ShiroAdminService;
import com.tool.shiro.service.ShiroPermissionService;
import com.tool.shiro.service.ShiroRoleService;
import com.tool.shiro.service.ShiroUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.security.Principal;
import java.util.List;

/**
 * 自定义shiro工具管理员Realm
 */
public class ShiroAdminRealm extends AuthorizingRealm {

    @Autowired
    private ShiroAdminService shiroAdminService;

    @Autowired
    private ShiroUserService shiroUserService;

    @Autowired
    private ShiroRoleService shiroRoleService;

    @Autowired
    private ShiroPermissionService shiroPermissionService;

    /**
     * 授权信息
     * @param principalCollection       管理员凭证信息
     * @return      授权信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获取身份信息[account]
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        ShiroAdminManage user = new ShiroAdminManage();
        user.setAccount(primaryPrincipal);
        user = shiroAdminService.findByAccount(user.getAccount());
        // 通过身份信息获取角色
        List<ShiroRole> shiroRoles = shiroAdminService.queryRolesByUser(user);
        // 如果角色信息不为空,授权角色信息
        if(!CollectionUtils.isEmpty(shiroRoles)) {
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            ShiroAdminManage finalUser = user;
            shiroRoles.forEach(role -> {
                // 添加授权信息
                simpleAuthorizationInfo.addRole(role.getName());
                // 获取不同角色可用权限
                List<ShiroPermission> shiroPermissions = shiroAdminService.queryPermissionsByUser(finalUser);
                // 如果权限集合不为空
                if (!CollectionUtils.isEmpty(shiroPermissions)) {
                    // 将权限集合循环添加到授权信息中
                    shiroPermissions.forEach(permission -> {
                        simpleAuthorizationInfo.addStringPermission(permission.getValue());
                    });
                }
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }

    /**
     * 认证信息
     * @param authenticationToken       管理员认证信息
     * @return      认证信息
     * @throws AuthenticationException  抛出认证错误
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 获取身份信息(用户登陆凭证[account])
        String principal = (String) authenticationToken.getPrincipal();
        // 通过登录凭证获取管理员信息
        ShiroAdminManage shiroAdmin = shiroAdminService.findByAccount(principal);
        // 如果管理员信息非空,返回认证信息
        if (!ObjectUtils.isEmpty(shiroAdmin)) {
            return new SimpleAuthenticationInfo(
                    shiroAdmin.getAccount(),
                    shiroAdmin.getPassword(),
                    new MyByteSource(shiroAdmin.getSalt()),
                    this.getName());
        }
        return null;
    }

    /**
     * 清除所有用户权限缓存
     */
    public void clearCacheAuthorizationInfo() {
        //this.clearCacheAuthorizationInfo((Principal) SecurityUtils.getSubject().getPrincipals());
        PrincipalCollection principalCollection = SecurityUtils.getSubject().getPrincipals();
        super.clearCachedAuthorizationInfo(principalCollection);
    }

    /**
     * 清除指定用户权限缓存
     * @param principal         用户身份信息
     */
    public void clearCacheAuthorizationInfo(Principal principal) {
        Subject subject = SecurityUtils.getSubject();
        SimplePrincipalCollection principalCollection = new SimplePrincipalCollection(principal, getName());
        subject.runAs(principalCollection);
        clearCacheAuthorizationInfo((Principal) subject.getPrincipals());
        subject.releaseRunAs();
    }

}
